<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>scripted_metric 聚合 | ElasticSearch 7.7 权威指南中文版</title>
	<meta name="keywords" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <meta name="description" content="ElasticSearch 权威指南中文版, elasticsearch 7, es7, 实时数据分析，实时数据检索" />
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
	<script>
	var _link = 'search-aggregations-metrics-scripted-metric-aggregation.html';
    </script>
</head>
<body>
<div class="main-container">
    <section id="content">
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-aggregations-metrics-scripted-metric-aggregation.html" rel="nofollow" target="_blank">https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-aggregations-metrics-scripted-metric-aggregation.html</a>, 原文档版权归 www.elastic.co 所有<br/>本地英文版地址: <a href="../en/search-aggregations-metrics-scripted-metric-aggregation.html" rel="nofollow" target="_blank">../en/search-aggregations-metrics-scripted-metric-aggregation.html</a></div>
                        <!-- start body -->
                  <div class="page_header">
<strong>重要</strong>: 此版本不会发布额外的bug修复或文档更新。最新信息请参考 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html" rel="nofollow">当前版本文档</a>。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch 权威指南 [7.7]</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations.html">聚合</a></span>
»
<span class="breadcrumb-link"><a href="search-aggregations-metrics.html">度量聚合</a></span>
»
<span class="breadcrumb-node">scripted_metric 聚合</span>
</div>
<div class="navheader">
<span class="prev">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">« percentile_ranks 聚合</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-string-stats-aggregation.html">string_stats 聚合 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="search-aggregations-metrics-scripted-metric-aggregation"></a>scripted_metric 聚合
</h2>
</div></div></div>
<p>使用脚本执行以提供度量输出的度量聚合。</p>
<p>示例：</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">POST ledger/_search?size=0
{
    "query" : {
        "match_all" : {}
    },
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : "state.transactions = []", <a id="CO204-1"></a><i class="conum" data-value="1"></i>
                "map_script" : "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
                "combine_script" : "double profit = 0; for (t in state.transactions) { profit += t } return profit",
                "reduce_script" : "double profit = 0; for (a in states) { profit += a } return profit"
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/382.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO204-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">init_script</code> 是一个可选的参数，其他的脚本都是必需的。</p>
</td>
</tr>
</table>
</div>
<p>上面的聚合演示了如何使用脚本聚合来计算销售和成本交易的总利润。</p>
<p>其响应如下:</p>
<div class="pre_wrapper lang-console-result">
<pre class="programlisting prettyprint lang-console-result">{
    "took": 218,
    ...
    "aggregations": {
        "profit": {
            "value": 240.0
        }
   }
}</pre>
</div>
<p>在上面的例子中也可以指定存储的脚本，如下所示:</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">POST ledger/_search?size=0
{
    "aggs": {
        "profit": {
            "scripted_metric": {
                "init_script" : {
                    "id": "my_init_script"
                },
                "map_script" : {
                    "id": "my_map_script"
                },
                "combine_script" : {
                    "id": "my_combine_script"
                },
                "params": {
                    "field": "amount" <a id="CO205-1"></a><i class="conum" data-value="1"></i>
                },
                "reduce_script" : {
                    "id": "my_reduce_script"
                }
            }
        }
    }
}</pre>
</div>
<div class="console_widget" data-snippet="snippets/383.console"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO205-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>
<code class="literal">init</code>、<code class="literal">map</code> 和 <code class="literal">combine</code> 脚本的脚本参数必须在全局 <code class="literal">params</code> 对象中指定，以便可以在脚本之间共享。
</p>
</td>
</tr>
</table>
</div>
<p>有关指定脚本的更多详细信息，请参考<a class="xref" href="modules-scripting.html" title="Scripting">脚本文档</a>。</p>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-return-types"></a>允许的返回类型
</h3>
</div></div></div>
<p>
虽然在单个脚本中可以使用任何有效的脚本对象，但是脚本必须在 <code class="literal">state</code> 对象中仅返回或存储以下类型：
</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
原始类型（primitive types）
</li>
<li class="listitem">
字符串（string）
</li>
<li class="listitem">
映射(map，仅包含此处列出的类型的键和值)
</li>
<li class="listitem">
数组(array，仅包含此处列出的类型的元素)
</li>
</ul>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-scope"></a>脚本的范围
</h3>
</div></div></div>
<p>脚本化度量聚合在其执行的 4 个阶段中使用脚本：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
init_script
</span>
</dt>
<dd>
<p>
在收集任何文件之前执行。允许聚合设置任何初始状态。
</p>
<p>在上面的例子中， <code class="literal">init_script</code> 在 <code class="literal">state</code> 对象中创建了一个数组 <code class="literal">transactions</code>。</p>
</dd>
<dt>
<span class="term">
map_script
</span>
</dt>
<dd>
<p>每个收集的文档执行一次。这是一个必需的脚本。如果没有指定 <code class="literal">combine_script</code>，那么结果状态需要存储在 <code class="literal">state</code> 对象中。</p>
<p>
在上面的示例中，<code class="literal">map_script</code> 检查 <code class="word">type</code> 字段的值。

如果值为<em>sale</em>，则<code class="word">amount</code>字段的值将被添加到<code class="literal">transactions</code>数组中。

如果 <code class="word">type</code> 字段的值不是<em>sale</em>，则将 <code class="word">amount</code> 字段取反的值添加到<code class="literal">transactions</code>中。
</p>
</dd>
<dt>
<span class="term">
combine_script
</span>
</dt>
<dd>
<p>文档收集完成后，在每个分片上执行一次。这是一个必需的脚本。允许聚合合并从每个分片返回的状态。</p>
<p>在上面的例子中，<code class="literal">combine_script</code> 遍历所有存储的<code class="literal">transactions</code>，对<code class="literal">profit</code>变量中的值求和，最后返回<code class="literal">profit</code>。</p>
</dd>
<dt>
<span class="term">
reduce_script
</span>
</dt>
<dd>
<p>
在所有分片返回结果后，在协调节点上执行一次。

这是一个必需的脚本。

该脚本提供了对变量 <code class="literal">states</code>的访问，该变量是每个分片上的 combine_script 结果的数组。
</p>
<p>在上面的例子中，<code class="literal">reduce_script</code> 遍历每个分片返回的 <code class="literal">profit</code>，对这些值求和，然后返回最终的组合的 profit(利润)，该利润将在聚合的响应中返回。</p>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-example"></a>工作示例
</h3>
</div></div></div>
<p>设想这样一种情况，你将下面的文档索引到一个包含两个分片的索引中：</p>
<div class="pre_wrapper lang-console">
<pre class="programlisting prettyprint lang-console">PUT /transactions/_bulk?refresh
{"index":{"_id":1}}
{"type": "sale","amount": 80}
{"index":{"_id":2}}
{"type": "cost","amount": 10}
{"index":{"_id":3}}
{"type": "cost","amount": 30}
{"index":{"_id":4}}
{"type": "sale","amount": 130}</pre>
</div>
<div class="console_widget" data-snippet="snippets/384.console"></div>
<p>
假设文档1和3最终在分片A上，文档2和4最终在分片B上。

下面是上例中每个阶段的汇总结果。
</p>
<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_before_init_script"></a>在 init_script 之前
</h4>
</div></div></div>
<p><code class="literal">state</code> 被初始化为一个新的空对象。</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {}</pre>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_init_script"></a>在 init_script 之后
</h4>
</div></div></div>
<p>在执行任何文档收集之前，这将在每个分片上运行一次，因此我们将在每个分片上有一个副本：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
分片 A
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : []
}</pre>
</div>
</dd>
<dt>
<span class="term">
分片 B
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : []
}</pre>
</div>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_map_script"></a>在 map_script 之后
</h4>
</div></div></div>
<p>每个分片收集它的文档，并在收集的每个文档上运行 map_script：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
分片 A
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : [ 80, -30 ]
}</pre>
</div>
</dd>
<dt>
<span class="term">
分片 B
</span>
</dt>
<dd>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"state" : {
    "transactions" : [ -10, 130 ]
}</pre>
</div>
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_combine_script"></a>在 combine_script 之后
</h4>
</div></div></div>
<p>
在文档收集完成后，在每个分片上执行 combine_script，并将所有 transactions 减少到每个分片的单个利润数字(通过对 transactions 数组中的值求和)，该数字被传递回协调节点：
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
分片 A
</span>
</dt>
<dd>
50
</dd>
<dt>
<span class="term">
分片 B
</span>
</dt>
<dd>
120
</dd>
</dl>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h4 class="title">
<a id="_after_reduce_script"></a>在 reduce_script 之后
</h4>
</div></div></div>
<p>reduce_script 接收一个 <code class="literal">states</code> 数组，其中包含每个分片的组合脚本的结果：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"states" : [
    50,
    120
]</pre>
</div>
<p>它将分片的响应减少到最终的总利润<span class="remark">(profit)</span>数值(通过对这些值求和)，并将其作为聚合的结果返回，以生成响应：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{
    ...

    "aggregations": {
        "profit": {
            "value": 170
        }
   }
}</pre>
</div>
</div>

</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-parameters"></a>其他参数
</h3>
</div></div></div>
<div class="informaltable">
<table border="0" cellpadding="4px">
<colgroup>
<col>
<col>
</colgroup>
<tbody valign="top">
<tr>
<td valign="top">
<p>
params
</p>
</td>
<td valign="top">
<p>
</p>
<p>
可选的。 

一个对象，其内容将作为变量传递给 <code class="literal">init_script</code>、<code class="literal">map_script</code> 和 <code class="literal">combine_script</code>。

这对于允许用户控制聚合行为以及存储脚本之间的状态非常有用。

如果未指定，默认情况下相当于指定了:
</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">"params" : {}</pre>
</div>

</td>
</tr>
</tbody>
</table>
</div>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="scripted-metric-aggregation-empty-buckets"></a>空桶
</h3>
</div></div></div>
<p>
如果脚本化度量聚合的父桶没有收集任何文档，将从分片返回一个值为 <code class="literal">null</code> 的空聚合响应。

在这种情况下，<code class="literal">reduce_script</code> 的 <code class="literal">states</code> 变量将包含 <code class="literal">null</code> 作为来自该分片的响应。

因此，<code class="literal">reduce_script</code> 应该期望并处理来自分片的 <code class="literal">null</code> 响应。
</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="search-aggregations-metrics-percentile-rank-aggregation.html">« percentile_ranks 聚合</a>
</span>
<span class="next">
<a href="search-aggregations-metrics-string-stats-aggregation.html">string_stats 聚合 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>